using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using Microsoft.DirectX;
using Visualization;

namespace VisualizationPackage.FileLoader
{
    public class Vertex : IComparable<Vertex>
    {
        private Dictionary<string, double> _values = new Dictionary<string, double>();

        public Dictionary<string, double> Values
        {
            get { return _values; }
            set { _values = value; }
        }
        public double X
        {
            get
            {
                if (!Values.ContainsKey(Constants.X_Coord))
                    Values[Constants.X_Coord] = 0;
                return Values[Constants.X_Coord];
            }
            set { Values[Constants.X_Coord] = value; }
        }
        public double Y
        {
            get
            {
                if (!Values.ContainsKey(Constants.Y_Coord))
                    Values[Constants.Y_Coord] = 0;
                return Values[Constants.Y_Coord];
            }
            set { Values[Constants.Y_Coord] = value; }
        }
        public double Z
        {
            get
            {
                if (!Values.ContainsKey(Constants.Z_Coord))
                    Values[Constants.Z_Coord] = 0;
                return Values[Constants.Z_Coord];
            }
            set { Values[Constants.Z_Coord] = value; }
        }

        public Vertex()
        {
        }
        public Vertex(double x, double y, double z)
        {
            X = x;
            Y = y;
            Z = z;
        }
        public Vertex(Visualization.Vertex vertex)
        {
            //_X = vertex.Position.x;
            //_Y = vertex.Position.y;
            //_Z = vertex.Position.z;
            for (int i = 0; i < vertex.Data.Length; i++)
                _values[GlobalVariables.Data[i].ToUpper()] = vertex.Data[i];
        }
        public double this[string distribution]
        {
            get
            {
                if (!Values.ContainsKey(distribution))
                {
                    // These commented lines will allow you to generate any custom variable does 
                    // not originally exist in the data file.
                    // Ref : 1.

                    //if (distribution == "R")
                    //    Values[distribution] = Math.Sqrt(X * X + Y * Y);
                    //else
                    Values[distribution] = 0;
                }
                return Values[distribution];
            }
            set
            {
                Values[distribution] = value;
            }
        }
        public static Vertex operator -(Vertex v1, Vertex v2)
        {
            Vertex v = new Vertex();
            foreach (string strValue in v1.Values.Keys)
                if (v2.Values.ContainsKey(strValue))
                    v[strValue] = v1[strValue] - v2[strValue];
            return v;
        }
        public static Vertex operator +(Vertex v1, Vertex v2)
        {
            Vertex v = new Vertex();
            foreach (string strValue in v1.Values.Keys)
                if (v2.Values.ContainsKey(strValue))
                    v[strValue] = v1[strValue] + v2[strValue];
            return v;
        }
        /// <summary>
        /// Cross Multiplication
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <returns></returns>
        public static Vertex operator *(Vertex v1, Vertex v2)
        {
            Vertex v = new Vertex();

            v.X = v1.Y * v2.Z - v1.Z * v2.Y;
            v.Y = v1.Z * v2.X - v1.X * v2.Z;
            v.Z = v1.X * v2.Y - v1.Y * v2.X;

            return v;
        }
        public static Vertex operator *(Vertex v, double value)
        {
            Vertex vRes = new Vertex();
            foreach (string key in v.Values.Keys)
                vRes[key] = v[key] * value;
            return vRes;
        }
        public static Vertex operator /(Vertex v, double value)
        {
            Vertex vRes = new Vertex();
            foreach (string key in v.Values.Keys)
                vRes[key] = v[key] / value;
            return vRes;
        }
        public double CrossMultiplyPositionVector(Vertex v)
        {
            double res = 0;
            //res += Y * v.Z - v.Y * Z;
            //res -= X * v.Z - v.X * Z;
            if (X != v.X)
                if (Y != v.Y)
                    res = X * v.Y - v.X * Y;
                else
                    res = X * v.Z - v.X * Z;
            else if (Y != v.Y)
                if (Z != v.Z)
                    res = Y * v.Z - v.Y * Z;
                else
                    res = X * v.Z - v.X * Z;
            else
                res = X * v.Z - v.X * Z;
            return res;
        }

        public double DotMultiplyPositionVector(Vertex v)
        {
            double res = 0;
            res += X * v.X;
            res += Y * v.Y;
            res += Z * v.Z;
            return res;
        }

        #region IComparable<Vertex> Members

        public int CompareTo(Vertex other)
        {
            return 0;
            /*
            double d = CrossMultiplyPositionVector(other);
            if (d > 0)
                return 1;
            if (d < 0)
                return -1;
            return 0;
            Vector3 v1 = new Vector3((float)X, (float)Y, (float)Z);
            Vector3 v2 = new Vector3((float)other.X, (float)other.Y, (float)other.Z);

            //float dot = Vector3.DotProduct(v1, v2);
            //dot /= v1.Length();
            //dot /= v2.Length();

            Vector3 vNormalTemp = Vector3.Cross(v1, v2);
            vNormalTemp.X /= (Math.Abs(vNormalTemp.X) == 0) ? 1 : Math.Abs(vNormalTemp.X);
            vNormalTemp.Y /= (Math.Abs(vNormalTemp.Y) == 0) ? 1 : Math.Abs(vNormalTemp.Y);
            vNormalTemp.Z /= (Math.Abs(vNormalTemp.Z) == 0) ? 1 : Math.Abs(vNormalTemp.Z);

            if (this == other)
                return 0;
            else if (vNormal == vNormalTemp)
                return 1;
            else if (vNormal == -1 * vNormalTemp)
                return -1;
            else
                throw new Exception("batata");

            float x = Vector3.Cross(v1, v2).Length();
            if (x > 0)
                return 1;
            if (x < 0)
                return -1;
            return 0;
            return (int)CrossMultiplyPositionVector(other);*/
        }

        #endregion
        public override bool Equals(object obj)
        {
            Vertex v = (Vertex)obj;
            foreach (string ind in Values.Keys)
                if (v.Values.ContainsKey(ind) && Math.Abs(v[ind] - Values[ind]) > 0.001)
                    return false;
            return true;
        }

        public static Vertex Interpolate(string SelectedDistribution, double p, Vertex v1, Vertex v2)
        {
            Vertex v = new Vertex();
            double diff = (v1[SelectedDistribution] - v2[SelectedDistribution]);
            double parameter = (p - v2[SelectedDistribution])
                / ((diff == 0) ? 1 : diff);
            v.X = v2.X + parameter * (v1.X - v2.X);
            v.Y = v2.Y + parameter * (v1.Y - v2.Y);
            v.Z = v2.Z + parameter * (v1.Z - v2.Z);
            v[SelectedDistribution] = p;
            return v;
        }
        public static Vertex InterpolatePosition(Vertex v1, Vertex v2, double parameter)
        {
            Vertex v = new Vertex();
            double x1 = v1.X;// Math.Min(v1.X, v2.X);
            double y1 = v1.Y;// Math.Min(v1.Y, v2.Y);
            double z1 = v1.Z;// Math.Min(v1.Z, v2.Z);

            double x2 = v2.X;// Math.Max(v1.X, v2.X);
            double y2 = v2.Y;// Math.Max(v1.Y, v2.Y);
            double z2 = v2.Z;// Math.Max(v1.Z, v2.Z);

            v.X = x1 + parameter * (x2 - x1);
            v.Y = y1 + parameter * (y2 - y1);
            v.Z = z1 + parameter * (z2 - z1);
            return v;
        }

        public Vertex Copy()
        {
            Vertex vertex = new Vertex();
            foreach (string key in Values.Keys)
                vertex[key] = Values[key];
            return vertex;
        }

        public double Magnitude()
        {
            return Math.Sqrt(X * X + Y * Y + Z * Z);
        }
        public override string ToString()
        {
            string ret = "Pos( " + Math.Round(X, 3).ToString() + ", " + Math.Round(Y, 3).ToString() + ", " + Math.Round(Z, 3).ToString() + " ) Data ( ";
            int count = 0;
            foreach (string strKey in Values.Keys)
            {
                count++;
                if (strKey != Constants.X_Coord && strKey != Constants.Y_Coord && strKey != Constants.Z_Coord)
                {
                    ret += Values[strKey];
                    if (count != Values.Count)
                        ret += ", ";
                    else
                        ret += " )";
                }
            }
            return ret;
        }
    }
    public class Line
    {
        private Vertex _vertex1;
        private Vertex _vertex2;
        private Color _drawingColor;

        public Color DrawingColor
        {
            get { return _drawingColor; }
            set { _drawingColor = value; }
        }
        public Vertex Vertex2
        {
            get { return _vertex2; }
            set { _vertex2 = value; }
        }
        public Vertex Vertex1
        {
            get { return _vertex1; }
            set { _vertex1 = value; }
        }

        public Line()
        {
        }
        public Line(Vertex v1, Vertex v2)
        {
            _vertex1 = v1;
            _vertex2 = v2;
        }
        public Line(Vertex v1, Vertex v2, Color DrawingColor)
            : this(v1, v2)
        {
            _drawingColor = DrawingColor;
        }
    }
    public class Polygon
    {
        private List<Vertex> _vertics = new List<Vertex>();
        private Color _drawingColor = Color.White;

        public Color DrawingColor
        {
            get { return _drawingColor; }
            set { _drawingColor = value; }
        }
        public List<Vertex> Vertics
        {
            get { return _vertics; }
            set { _vertics = value; }
        }

        public void Sort()
        {
            Vertex v = _vertics[0];
            int ind = 0;
            for (int i = 0; i < _vertics.Count; i++)
            {
                if (_vertics[i].X < v.X)
                {
                    v = _vertics[i];
                    ind = i;
                }
                else if (_vertics[i].Y < v.Y)
                {
                    v = _vertics[i];
                    ind = i;
                }
                else if (_vertics[i].Z < v.Z)
                {
                    v = _vertics[i];
                    ind = i;
                }
            }
            _vertics[ind] = _vertics[0];
            _vertics[0] = v;
            /*
            Vertex _v1 = _vertics[1] - _vertics[0];
            Vector3 v1 = new Vector3((float)_v1.X, (float)_v1.Y, (float)_v1.Z);
            Vertex _v2 = _vertics[2] - _vertics[0];
            Vector3 v2 = new Vector3((float)_v2.X, (float)_v2.Y, (float)_v2.Z);
            Vector3 vNormal = Vector3.Cross(v1, v2);
            vNormal.X /= Math.Abs((vNormal.X == 0) ? 1 : vNormal.X);
            vNormal.Y /= Math.Abs((vNormal.Y == 0) ? 1 : vNormal.Y);
            vNormal.Z /= Math.Abs((vNormal.Z == 0) ? 1 : vNormal.Z);
            _vertics[0].vNormal = vNormal;
            
            for (int i = 1; i < _vertics.Count; i++)
            {
                _vertics[i].vNormal = vNormal;
                _vertics[i] = _vertics[i] - _vertics[0];
            }*/
            /*
            for(int i=0; i<_vertics.Count; i++)
                for (int j = 1; j < _vertics.Count; j++)
                {
                    if (_vertics[j].CompareTo(_vertics[j - 1]) < 0)
                    {
                        Vertex vTemp = _vertics[j];
                        _vertics[j] = _vertics[j - 1];
                        _vertics[j - 1] = vTemp;
                    }
                }
            
            _vertics.Sort(1, _vertics.Count - 1, null);

            for (int i = 1; i < _vertics.Count; i++)
                _vertics[i] = _vertics[i] + _vertics[0];
             */
        }
        /*
        public int Comparer(Vertex v1, Vertex v2)
        {
            if (v1 == null || v2 == null)
                return 0;
            Vertex V1 = v1 - _vertics[0];
            Vertex V2 = v2 - _vertics[0];
            return (int)Math.Acos((int)V1.DotMultiplyPositionVector(V2));

            double sin = V1.CrossMultiplyPositionVector(V2);
            double cos = Math.Acos(V1.DotMultiplyPositionVector(V2));
            if (sin < 0)
                return (int)(2 * Math.PI - cos);
            return (int)cos;
        }*/

        internal void Add(Vertex vertex)
        {
            if (_vertics.Contains(vertex))
                return;
            _vertics.Add(vertex);
        }
        public void Add(Visualization.Vertex vertex)
        {
            if (!_vertics.Contains(new Vertex(vertex)))
                _vertics.Add(new Vertex(vertex));
        }
        public override string ToString()
        {
            return Vertics.Count.ToString();
        }
    }
    public class Zone
    {
        #region Data members
        private List<Vertex> _vertics = new List<Vertex>();
        private List<int> _topology = new List<int>();
        private string _name;
        private int _nVertics;
        private int _elements;
        private ElementType _elementType;
        private Format _format;
        #endregion
        #region Properties
        public List<int> Topology
        {
            get { return _topology; }
            set { _topology = value; }
        }
        public Format Format
        {
            get { return _format; }
            set { _format = value; }
        }
        public ElementType ElementType
        {
            get { return _elementType; }
            set { _elementType = value; }
        }
        public int Elements
        {
            get { return _elements; }
            set { _elements = value; }
        }
        public int nVertics
        {
            get { return _nVertics; }
            set { _nVertics = value; }
        }
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public List<Vertex> Vertics
        {
            get { return _vertics; }
            set { _vertics = value; }
        }
        #endregion
    }
    public enum ElementType
    {
        Brick = 1,
        Tetrahedron,
        Triangle,
        Quadrilateral
    }
    public enum Format
    {
        FPoint,
        FBlock
    }
}
